#include "triangle.h"
#include <QDateTime>

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
GLuint VBO, VAO, lightVAO;

const char *vertexShaderSource =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;"
        "layout (location = 1) in vec3 aNormal;"
        "layout (location = 2) in vec2 aTexCoords;"
        "out vec2 TexCoords;"
        "out vec3 Normal;"
        "out vec3 FragPos;"

        "uniform mat4 model;"
        "uniform mat4 view;"
        "uniform mat4 projection;"

        "void main()"
        "{"
        "   FragPos = vec3(model * vec4(aPos, 1.0));"
        "   Normal = mat3(transpose(inverse(model))) * aNormal;  "
        "   gl_Position = projection * view * vec4(aPos, 1.0);"
        "   TexCoords = aTexCoords;"
        "}";

const char *fragmentShaderSource =
        "#version 330 core\n"
        "out vec4 FragColor;"
        "in vec2 TexCoords;"
        "in vec3 FragPos;"
        "in vec3 Normal;"
        "uniform vec3 viewPos;"
        "struct Light {"
        "    vec3 direction;"
        "    vec3 ambient;"
        "    vec3 diffuse;"
        "    vec3 specular;"
        "};"

        "uniform sampler2D texture_diffuse1;"
        "uniform Light light;"
        "void main(){"
        "   vec3 ambient = light.ambient * texture(texture_diffuse1, TexCoords).rgb;"
        // diffuse
        "   vec3 norm = normalize(Normal);"
        "   vec3 lightDir = normalize(-light.direction);"
        "   float diff = max(dot(norm, lightDir), 0.0);"
        "   vec3 diffuse = light.diffuse * diff * texture(texture_diffuse1, TexCoords).rgb;"
        // specular
        "   vec3 viewDir = normalize(viewPos - FragPos);"
        "   vec3 reflectDir = reflect(-lightDir, norm);  "
        "   float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0f);"
        "   vec3 specular = light.specular * spec * texture(texture_diffuse1, TexCoords).rgb; "

        "   vec3 result = ambient + diffuse + specular;"

        "   FragColor = vec4(result, 1.0);"
        "}";

const char *lightColorVs =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;"   // 位置变量的属性位置值为 0
        "uniform mat4 model;"
        "uniform mat4 view;"
        "uniform mat4 projection;"

        "void main(){"
        "   gl_Position = projection * view * model * vec4(aPos, 1.0);"
        "}";

const char *lightColorFs =
        "#version 330 core\n"
        "out vec4 FragColor;"
        "void main()"
        "{"
        "   FragColor = vec4(1.0);"
        "}";

Triangle::Triangle(){

}

Triangle::~Triangle(){

}

void Triangle::initializeGL(){
    this->resize(1000,800);
    //着色器部分
    this->initializeOpenGLFunctions();
    // 监听键盘
    this->releaseKeyboard();
    // 开启深度测试
    glEnable(GL_DEPTH_TEST);

    shader = std::make_shared<Shader>(this);
    lightShader = std::make_shared<Shader>(this);

    shader->readShaderStr(vertexShaderSource, fragmentShaderSource);
    lightShader->readShaderStr(lightColorVs, lightColorFs);

    ourModel = std::make_shared<Model>("D:/Material/nanosuit/nanosuit.obj", this);

    time.start();
}

void Triangle::resizeGL(int w, int h){
    QExpandOpenGLWidget::resizeGL(w, h);
}

void Triangle::paintGL(){
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    shader->use();

    // view/projection transformations
    glm::mat4 view =  glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
    shader->setMat4("projection", projection);
    shader->setMat4("view", view);
    shader->setVec3("light.direction", -0.2f, -1.0f, -0.3f);
    shader->setVec3("viewPos", cameraPos);

    // light properties
    shader->setVec3("light.ambient", 0.2f, 0.2f, 0.2f);
    shader->setVec3("light.diffuse", 0.5f, 0.5f, 0.5f);
    shader->setVec3("light.specular", 1.0f, 1.0f, 1.0f);

    // render the loaded model
    glm::mat4 model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); // translate it down so it's at the center of the scene
    model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f));	// it's a bit too big for our scene, so scale it down
    shader->setMat4("model", model);
    ourModel->Draw(*shader);

    glUseProgram(0);
    this->update();
}

void Triangle::keyPressEvent(QKeyEvent *event){
    QExpandOpenGLWidget::keyPressEvent(event);
}

void Triangle::mouseReleaseEvent(QMouseEvent* event){
    QExpandOpenGLWidget::mouseReleaseEvent(event);
}


void Triangle::mousePressEvent(QMouseEvent *event) {
    QExpandOpenGLWidget::mousePressEvent(event);
}

void Triangle::mouseMoveEvent(QMouseEvent* event){
    QExpandOpenGLWidget::mouseMoveEvent(event);
}


void Triangle::wheelEvent(QWheelEvent *event) {
    QExpandOpenGLWidget::wheelEvent(event);
}
